import {useCallback, useEffect, useRef, useState} from "react";
import {Token} from "types/user";
import {useDispatch, useSelector} from "react-redux";
import * as auth from "store/modules/user";
import {selectMenu, selectRole, selectUser} from "store/modules/user";
import {AuthForm} from "views/login";
import {removeCookie} from "./cookies";

/*
    useEffect 只加载一次 hook必须以use开头
*/
export const useMount = (callback: () => void) => {
    useEffect(() => {
        callback();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);
};

/**
 * 返回组件的挂载状态，如果还没挂载或者已经卸载，返回false；反之，返回true
 */
export const useMountedRef = () => {
    const mountedRef = useRef(false);
    useEffect(() => {
        mountedRef.current = true;
        return () => {
            mountedRef.current = false;
        };
    });
    return mountedRef;
};

// 泛型规范类型
export const useDebounce = <D>(value: D, delay?: number) => {
    const [debounceValue, setDebounceValue] = useState(value);
    useEffect(() => {
        const timeout = setTimeout(() => setDebounceValue(value), delay);
        return () => clearTimeout(timeout);
    }, [value, delay]);
    return debounceValue;
}

export const useAuth = () => {
    const user = useSelector(selectUser);
    const menu = useSelector(selectMenu);
    const role = useSelector(selectRole);
    const dispatch: (...args: any[]) => Promise<Token> = useDispatch()
    const login = useCallback((form: AuthForm) => dispatch(auth.login(form)), [dispatch])
    const logout = useCallback(() => {
        removeCookie('mic-token')
        return dispatch(auth.logout())
    }, [dispatch])
    const getInfo = useCallback(() => dispatch(auth.getInfo()), [dispatch])
    return {user, role, menu, login, logout, getInfo}
}

interface useObjectStateType {
    (value: object): void
}

export const useObjectState = <S>(initialState: S | (() => S)): [S, useObjectStateType] => {
    const [data, setDatas] = useState(initialState)
    const setData: useObjectStateType = (value) => {
        setDatas((newData) => {
            return ({
                ...newData,
                ...value
            })
        })
    }
    return [data, setData]
}
